home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / PI.C < prev    next >
C/C++ Source or Header  |  1996-12-28  |  40KB  |  1,435 lines

  1. #ifdef MSDOS
  2. /*
  3.  * Interface driver for the VE3IFB 8530 card (PI card)
  4.  * Copyright 1990 by Dave Perry, VE3IFB
  5.  *
  6.  * History
  7.  * Minor delinting - KA9Q 2/2/91
  8.  * March 23 92 dp - Fixed bug in B port driver where ff in the data was
  9.  *                not being handled correctly. 
  10.  *              - Fixed bug where receive packet would get clobbered if
  11.  *                a new packet was enqueued for transmission. Greatly
  12.  *                improves performance with sliding window protocols.
  13.  *                (tdelay would overwrite contents of the interrupt control
  14.  *                register in the scc).
  15.  * March 29,92 dp - Last release was based on old sources - corrected.
  16.  * 
  17.  *
  18.  * Portions of this driver were derived from the Eagle card
  19.  * driver by Art Goldman, WA3CVG. It has been very extensively
  20.  * modified from his work, due to the addition of DMA support
  21.  * and due to differences in the hardware.  The PI card is NOT
  22.  * an Eagle card clone. It is an original design by Dave Perry,
  23.  * VE3IFB.  Art's copyright notice follows:
  24.  *
  25.  *  Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
  26.  *  Permission for non-commercial use is hereby granted provided this notice
  27.  *  is retained.  For info call: (301) 997-3838.
  28.  *
  29.  */
  30.  
  31. #include "global.h"
  32. #ifdef PI
  33. #include <time.h>
  34. #include <dos.h>
  35. #include <bios.h>
  36. #include "mbuf.h"
  37. #include "iface.h"
  38. #include "pktdrvr.h"
  39. #include "netuser.h"
  40. #include "pi.h"
  41. #include "z8530.h"
  42. #include "ax25.h"
  43. #include "trace.h"
  44. #include "pc.h"
  45.  
  46. #include "session.h"
  47. #include "lapb.h"
  48. #include "proc.h"
  49. #include "ip.h"
  50. #include "devparam.h"
  51.  
  52. #if !defined(_lint)
  53. static char rcsid[] OPTIONAL = "$Id: pi.c,v 1.14 1996/12/29 02:47:22 root Exp root $";
  54. #endif
  55.  
  56. #ifndef FP_OFF
  57. #define FP_OFF(fp)    ((unsigned)(fp))
  58. #endif
  59. #ifndef FP_SEG
  60. #define FP_SEG(fp)    ((unsigned)((unsigned long)(fp) >> 16))
  61. #endif
  62.  
  63. static int32 pi_ctl (struct iface *iface,int cmd,int set,int32 val);
  64. static int pi_raw (struct iface *iface,struct mbuf *bp);
  65. static int pi_stop (struct iface *iface);
  66. static void rts (struct pichan *hp, int16 x);
  67. void setup_rx_dma (struct pichan *hp);
  68. void setup_tx_dma (struct pichan *hp, char *buffer, int length);
  69. static void tdelay (register struct pichan *hp,unsigned int time);
  70.  
  71. static void b_txint (register struct pichan *hp);
  72. static void b_exint (register struct pichan *hp);
  73. static void b_rxint (register struct pichan *hp);
  74. void a_txint (register struct pichan *hp);
  75. static void a_rxint (register struct pichan *hp);
  76. static void a_exint (register struct pichan *hp);
  77. static int scc_init (register struct pichan *hp);
  78. extern void set_acc_delay (void);
  79.  
  80. static struct PITAB Pi[PIMAX];    /* Device table - one entry per card */
  81. static void (*pihandle[])() = {    /* handler interrupt vector table */
  82.     pi0vec,
  83.     pi1vec,
  84.     pi2vec
  85. };
  86. static int16 Page_regs[] = {
  87.     0x87,0x83,0x81,0x82,0,0x8b,0x89,0x8a
  88. };
  89. static struct pichan Pichan[2*PIMAX];    /* channel table - 2 entries per card */
  90. static int16 pinbr;
  91.  
  92. extern int16 acc_delay;    /* Delay for the 8530 chip access recovery time */
  93.  
  94. /* Setup 8253 chip for time delay */
  95. static void
  96. tdelay(hp,time)
  97. register struct pichan *hp;
  98. unsigned int time;         /* Time to delay in milliseconds */
  99. {
  100.     int n,port;
  101.     unsigned int t1;
  102.     unsigned char sc;
  103.  
  104.     if(hp->base & 2){ /* If A channel */
  105.         sc = SC1;
  106.         t1 = time;
  107.         port = hp->cardbase+TMR1;
  108.     } else {
  109.         sc = SC2;
  110.         t1 = 10 * time; /* 10s of milliseconds for the B channel */
  111.         port = hp->cardbase+TMR2;
  112.         wrtscc(hp->cardbase,hp->base+CTL,R1,EXT_INT_ENAB);
  113.     }
  114.  
  115.     /* Setup timer sc */
  116.     outportb(hp->cardbase+TMRCMD, sc|LSB_MSB|MODE0);
  117.     
  118.     /* satisfy access time restriction */
  119.     for(n=0; n<2;n++)
  120.         ;
  121.     /* times 2 to make millisecs */
  122.     outportb(port, (t1 << 1) & 0xFF);
  123.  
  124.     /* satisfy access time restriction */
  125.     for(n=0; n<2;n++)
  126.         ;
  127.     outportb(port, (t1 >> 7) & 0xFF);
  128.  
  129.     /* Enable correct int for timeout */
  130.     wrtscc(hp->cardbase,hp->base+CTL,R15,CTSIE);
  131.     wrtscc(hp->cardbase,hp->base+CTL,R0,RES_EXT_INT);
  132. }
  133.  
  134. /* Master interrupt handler.  One interrupt at a time is handled.
  135.  * here. Service routines are called from here.
  136.  */
  137. void
  138. piint(dev)
  139. int dev;
  140. {
  141.     register char st;
  142.     register int16 pcbase;
  143.     struct pichan *hp;
  144.  
  145.     Pi[dev].ints++;
  146.     pcbase = Pi[dev].addr;
  147.  
  148.     /* Read interrupt status register (only valid from channel A)
  149.      * Process all pending interrupts in while loop
  150.      */
  151.     hp = &Pichan[2 * dev];    /* Assume channel A */
  152.     while((st = rdscc(hp->cardbase,pcbase+CHANA+CTL,R3)) != 0){
  153.         if(st & CHBTxIP){
  154.             /* Channel B Transmit Int Pending */
  155.             hp = &Pichan[(2 * dev)+1];
  156.             b_txint(hp);
  157.         } else if(st & CHARxIP){
  158.             /* Channel A Rcv Interrupt Pending */
  159.             hp = &Pichan[2 * dev];
  160.             a_rxint(hp);
  161.         } else if(st & CHATxIP){
  162.             /* Channel A Transmit Int Pending */
  163.             hp = &Pichan[2 * dev];
  164.             a_txint(hp);
  165.         } else if(st & CHAEXT){
  166.             /* Channel A External Status Int */
  167.             hp = &Pichan[2 * dev];
  168.             a_exint(hp);
  169.         } else if(st & CHBRxIP){
  170.             /* Channel B Rcv Interrupt Pending */
  171.             hp = &Pichan[(2 * dev)+1];
  172.             b_rxint(hp);
  173.         } else if(st & CHBEXT){
  174.             /* Channel B External Status Int */
  175.             hp = &Pichan[(2 * dev)+1];
  176.             b_exint(hp);
  177.         }
  178.         /* Reset highest interrupt under service */
  179.         wrtscc(hp->cardbase,hp->base+CTL,R0,RES_H_IUS);
  180.     } /* End of while loop on int processing */
  181. }
  182.  
  183. static void
  184. a_exint(hp)
  185. register struct pichan *hp;
  186. {
  187.     register int16 cmd;
  188.     char st, i_state;
  189.     int length;
  190.     int32 t,ca;
  191.  
  192.     i_state = disable ();        /* disable interrupts */
  193.  
  194.     st = rdscc(hp->cardbase,hp->base+CTL,R0);     /* Fetch status */
  195.  
  196.     /* reset external status latch */
  197.     wrtscc(hp->cardbase,CTL+hp->base,R0,RES_EXT_INT);
  198.     cmd = hp->base+CTL;
  199.     hp->exints++;
  200.  
  201.     if((hp->rstate >= ACTIVE) && (st & BRK_ABRT)){    
  202.         setup_rx_dma(hp);
  203.         hp->rstate = ACTIVE;
  204.     }
  205.     switch(hp->tstate){
  206.     case ACTIVE:
  207.         free_p(hp->sndbuf);
  208.         hp->sndbuf = NULLBUF;
  209.         hp->tstate = FLAGOUT;
  210.         tdelay(hp,hp->squeldelay);
  211.         break;
  212.     case FLAGOUT:
  213.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  214.             /* Nothing to send - return to receive mode */
  215.             hp->tstate = IDLE;
  216.             rts(hp,OFF);
  217.             restore(i_state);
  218.             return;
  219.         }
  220.         /* NOTE - fall through if more to send */
  221.     case ST_TXDELAY:
  222.         /* Disable DMA chan */
  223.         outportb(DMA_MASK, DMA_DISABLE|hp->dmachan);
  224.  
  225.         /* Set up for TX dma */
  226.         wrtscc(hp->cardbase,cmd,R1,WT_FN_RDYFN|EXT_INT_ENAB);
  227.  
  228.         /* Get all chars */
  229.         length = pullup(&hp->sndbuf,hp->txdmabuf,hp->bufsiz);
  230.  
  231.         /* Setup DMA controller for tx */
  232.         setup_tx_dma(hp,hp->txdmabuf,length);
  233.  
  234.         /* select transmit interrupts to enable */
  235.         /* Allow DMA on chan */
  236.         outportb(DMA_MASK,DMA_ENABLE|hp->dmachan);
  237.  
  238.         /* reset CRC, Txint pend*/
  239.         wrtscc(hp->cardbase,cmd,R0,RES_Tx_CRC|RES_Tx_P);
  240.  
  241.         /* allow Underrun int only */
  242.         wrtscc(hp->cardbase,cmd,R15,TxUIE);
  243.  
  244.         /* Enable TX DMA */
  245.         wrtscc(hp->cardbase,cmd,R1,WT_RDY_ENAB|WT_FN_RDYFN|EXT_INT_ENAB);
  246.  
  247.         /* Send CRC on underrun */
  248.         wrtscc(hp->cardbase,cmd,R0,RES_EOM_L);
  249.  
  250.         /* packet going out now */
  251.         hp->tstate = ACTIVE;
  252.         break;
  253.     case DEFER:
  254.         /* we have deferred prev xmit attempt
  255.          * See Intel Microcommunications Handbook, p2-308
  256.          */
  257.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  258.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  259.         if((rdscc(hp->cardbase,cmd,R0) & DCD) != 0){
  260.             hp->tstate = DEFER;
  261.             tdelay(hp,100);
  262.             /* Defer until dcd transition or 100mS timeout */
  263.             wrtscc(hp->cardbase,CTL+hp->base,R15,CTSIE|DCDIE);
  264.             restore(i_state);
  265.             return;
  266.         }
  267.  
  268.         if((rand() & 0xff) > uchar(hp->persist)){
  269.             hp->tstate = DEFER;
  270.             tdelay(hp,hp->slotime);
  271.             restore(i_state);
  272.             return;
  273.         }
  274.         /* Assert RTS early minimize collision window */
  275.         wrtscc(hp->cardbase,cmd,R5,TxCRC_ENAB|RTS|Tx8);
  276.         rts(hp,ON);    /* Transmitter on */
  277.         hp->tstate = ST_TXDELAY;
  278.         tdelay(hp,hp->txdelay);
  279.         restore(i_state);
  280.         return;
  281.     } /* switch(hp->tstate) */
  282.  
  283.     restore(i_state);
  284. } /* a_exint() */
  285.  
  286. /* Receive interrupt handler for the A channel 
  287.  */
  288. static void
  289. a_rxint(hp)
  290. register struct pichan *hp;
  291. {
  292.     register int16 cmd;
  293.     register int16 bytecount;
  294.     char rse, i_state;
  295.     struct mbuf *bp;
  296.     struct phdr phdr;
  297.  
  298.     i_state = disable ();        /* disable interrupts */
  299.     hp->rxints++;
  300.     cmd = hp->base+CTL;
  301.  
  302.     rse = rdscc(hp->cardbase,cmd,R1); /* Get special condition bits from R1 */
  303.     if(rse & Rx_OVR)
  304.         hp->rstate = RXERROR;
  305.  
  306.     if(rse & END_FR){
  307.         /* If end of frame */
  308.         /* figure length of frame from 8237 */
  309.         outportb(DMA_RESETFF,0); /* reset firstlast ff */
  310.         bytecount = inportb(hp->dma_wcr);
  311.         bytecount += inportb(hp->dma_wcr) << 8;
  312.         /* Allow for the extra space for phdr */
  313.         bytecount = (hp->bufsiz - 1 - sizeof(struct phdr)) - bytecount;
  314.  
  315.         if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(bytecount < 10)){
  316.             if((bytecount >= 10) && (rse & CRC_ERR))
  317.                 hp->crcerr++; /* Ignore noise */
  318.  
  319.             if(hp->rstate == RXERROR)
  320.                 hp->rovers++;
  321.             /* Reset buffer pointers */
  322.             hp->rstate = ACTIVE;
  323.             setup_rx_dma(hp);
  324.         } else {
  325.             /* Here we have a valid frame */
  326.             /* Toss 2 crc bytes */
  327.             hp->rcvbuf->cnt = bytecount - 2;
  328.             /* "Can't fail" */
  329.             bp = pushdown(hp->rcvbuf,sizeof(phdr));
  330.             phdr.type = CL_AX25;
  331.             phdr.iface = hp->iface;
  332.             memcpy(bp->data,(char *)&phdr,sizeof(phdr));
  333.             hp->rcvbuf = NULLBUF;
  334.             enqueue(&Hopper,bp);       /* queue it in */
  335.             hp->rxframes++;
  336.  
  337.             /* packet queued - get buffer for next frame */
  338.             hp->rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(phdr));
  339.             if(hp->rcvbuf != NULLBUF)
  340.                 /* Allow room for phdr */
  341.                 hp->rcvbuf->data += sizeof(struct phdr);
  342.             setup_rx_dma(hp);
  343.         } /* end good frame queued */
  344.     } /* end EOF check */
  345.  
  346.     wrtscc(hp->cardbase,hp->base+CTL,R0,ERR_RES);    /* error reset */
  347.     restore(i_state);
  348. }
  349.  
  350. void
  351. a_txint(hp)
  352. register struct pichan *hp;
  353. {
  354.     register int16 cmd;
  355.     char i_state;
  356.     int32 t,ca;
  357.  
  358.     i_state = disable ();
  359.     cmd = CTL+hp->base;
  360.  
  361.     switch(hp->tstate){
  362.     case IDLE:
  363.         /* Transmitter idle. Find a frame for transmission */
  364.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  365.             rts(hp,OFF);
  366.             restore(i_state);
  367.             return;
  368.         }
  369.         /* If a buffer to send, we drop thru here */
  370.     case DEFER:
  371.         /* we may have deferred prev xmit attempt */
  372.         /* Check DCD - debounce it
  373.          * See Intel Microcommunications Handbook, p2-308
  374.          */
  375.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  376.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  377.         if((rdscc(hp->cardbase,cmd,R0) & DCD) != 0){
  378.             hp->tstate = DEFER;
  379.             tdelay(hp,100);
  380.             /* defer until DCD transition or timeout */
  381.             wrtscc(hp->cardbase,cmd,R15,CTSIE|DCDIE);
  382.             restore(i_state);
  383.             return;
  384.         }
  385.  
  386.         if((rand() & 0xff) > uchar(hp->persist)){
  387.             hp->tstate = DEFER;
  388.             tdelay(hp,hp->slotime);
  389.             restore(i_state);
  390.             return;
  391.         }
  392.  
  393.         /* Assert RTS early minimize collision window */
  394.         wrtscc(hp->cardbase,cmd,R5,TxCRC_ENAB|RTS|Tx8);
  395.         rts(hp,ON);    /* Transmitter on */
  396.         hp->tstate = ST_TXDELAY;
  397.         tdelay(hp,hp->txdelay);
  398.         restore(i_state);
  399.         return;
  400.     default:
  401.         break;
  402.     } /* end switch(hp->state) */
  403.  
  404.     restore(i_state);
  405. } /*a_txint */
  406.  
  407. static void
  408. b_rxint(hp)
  409. register struct pichan *hp;
  410. {
  411.     register int16 cmd;
  412.     char rse, i_state;
  413.     struct mbuf *bp;
  414.     struct phdr phdr;
  415.  
  416.     i_state = disable ();        /* disable interrupts */
  417.     hp->rxints++;
  418.     cmd = CTL+hp->base;
  419.  
  420.     if((rdscc(hp->cardbase,cmd,R0)) & Rx_CH_AV){
  421.         /* there is a char to be stored
  422.          * read special condition bits before reading the data char
  423.          */
  424.         rse = rdscc(hp->cardbase,cmd,R1); /* get status byte from R1 */
  425.         if(rse & Rx_OVR){
  426.             /* Rx overrun - toss buffer */
  427.             /* reset buffer pointers */
  428.             hp->rcp = hp->rcvbuf->data;
  429.             hp->rcvbuf->cnt = 0;
  430.             hp->rstate = RXERROR;    /* set error flag */
  431.             hp->rovers++;
  432.         } else if(hp->rcvbuf->cnt >= hp->bufsiz - sizeof(struct phdr)){
  433.             /* Too large -- toss buffer */
  434.             /* reset buffer pointers */
  435.             hp->rcp = hp->rcvbuf->data;
  436.             hp->rcvbuf->cnt = 0;
  437.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  438.         }
  439.         /* ok, we can store the received character now */
  440.         if(hp->rstate == ACTIVE){    /* If no errors... */
  441.             *hp->rcp++ = rdscc(hp->cardbase,cmd,R8); /* char to rcv buff */
  442.             hp->rcvbuf->cnt++;           /* bump count */
  443.         } else {
  444.             /* got to empty FIFO */
  445.             (void) rdscc(hp->cardbase,cmd,R8);
  446.             wrtscc(hp->cardbase,cmd,R0,ERR_RES);    /* reset err latch */
  447.             hp->rstate = ACTIVE;
  448.         }
  449.     }
  450.  
  451.     if(rse & END_FR){
  452.         /* END OF FRAME -- Make sure Rx was active */
  453.         if(hp->rcvbuf->cnt > 0){
  454.             if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(hp->rcvbuf->cnt < 10)){
  455.                 if((hp->rcvbuf->cnt >= 10) && (rse & CRC_ERR))
  456.                     hp->crcerr++; /* Ignore noise */
  457.  
  458.                 hp->rcp = hp->rcvbuf->data;
  459.                 hp->rcvbuf->cnt = 0;
  460.             } else {
  461.                 /* Here we have a valid frame */
  462.                 hp->rcvbuf->cnt -= 2;  /* Toss 2 crc bytes */
  463.                 /* "Can't fail" */
  464.                 bp = pushdown(hp->rcvbuf,sizeof(phdr));
  465.                 phdr.type = CL_AX25;
  466.                 phdr.iface = hp->iface;
  467.                 memcpy(bp->data,(char *)&phdr,sizeof(phdr));
  468.                 enqueue(&Hopper,bp);       /* queue it in */
  469.                 hp->rxframes++;
  470.  
  471.                 /* packet queued - get buffer for next frame */
  472.                 hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
  473.                 if(hp->rcvbuf == NULLBUF){
  474.                     /* No memory - abort rx */
  475.                     wrtscc(hp->cardbase,cmd,R3,Rx8);
  476.                     restore(i_state);
  477.                     return;
  478.                 }
  479.                 hp->rcvbuf->data += sizeof(struct phdr);
  480.                 hp->rcp = hp->rcvbuf->data;
  481.                 hp->rcvbuf->cnt = 0;
  482.             } /* end good frame queued */
  483.         }  /* end check for active receive upon EOF */
  484.         hp->rstate = ACTIVE;    /* and clear error status */
  485.     } /* end EOF check */
  486.  
  487.     restore(i_state);
  488. }
  489.  
  490. static void
  491. b_txint(hp)
  492. register struct pichan *hp;
  493. {
  494.     register int16 cmd;
  495.     char i_state;
  496.     int c;
  497.  
  498.     i_state = disable ();
  499.     cmd = CTL+hp->base;
  500.  
  501.     if(hp->tstate != DEFER && hp->tstate)
  502.         hp->txints++;
  503.  
  504.     switch(hp->tstate){
  505.     case CRCOUT:
  506.         hp->tstate = FLAGOUT;
  507.         tdelay(hp,hp->squeldelay);
  508.         restore(i_state);
  509.         return;
  510.     case IDLE:
  511.         /* Transmitter idle. Find a frame for transmission */
  512.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  513.             /* Nothing to send - return to receive mode
  514.              * Tx OFF now - flag should have gone
  515.              */
  516.             rts(hp,OFF);
  517.             restore(i_state);
  518.             return;
  519.         }
  520.         /* If a buffer to send, we drop thru here */
  521.     case DEFER:        /* we may have deferred prev xmit attempt */
  522.         /* Check DCD - debounce it */
  523.         /* See Intel Microcommunications Handbook, p2-308 */
  524.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  525.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  526.         if((rdscc(hp->cardbase,cmd,R0) & DCD) != 0){
  527.             hp->tstate = DEFER;
  528.             tdelay(hp,100);
  529.             /* defer until DCD transition or timeout */
  530.             wrtscc(hp->cardbase,cmd,R15,CTSIE|DCDIE);
  531.             restore(i_state);
  532.             return;
  533.         }
  534.         /* p - persist calculation */
  535.         if(inportb(hp->cardbase+TMR0) > hp->persist){
  536.             inportb(hp->cardbase+TMR0); /* Discard MSB */
  537.             hp->tstate = DEFER;
  538.             tdelay(hp,hp->slotime);
  539.             restore(i_state);
  540.             return;
  541.         }
  542.         inportb(hp->cardbase+TMR0); /* Discard MSB */
  543.  
  544.         rts(hp,ON);   /* Transmitter on */
  545.         hp->tstate = ST_TXDELAY;
  546.         tdelay(hp,hp->txdelay);
  547.         restore(i_state);
  548.         return;
  549.  
  550.     case ACTIVE:
  551.         /* Here we are actively sending a frame */
  552.         if((c = PULLCHAR(&hp->sndbuf)) != -1){
  553.             /* next char is gone */
  554.             wrtscc(hp->cardbase,cmd,R8,c);
  555.             /* stuffing a char satisfies Interrupt condition */
  556.         } else {
  557.             /* No more to send */
  558.             free_p(hp->sndbuf);
  559.             if((rdscc(hp->cardbase,cmd,R0) & 0x40)){
  560.                 /* Did we underrun? */
  561.                 /* unexpected underrun */
  562.                 hp->tunders++;
  563.                 wrtscc(hp->cardbase,cmd,R0,SEND_ABORT);
  564.                 hp->tstate = FLAGOUT;
  565.                 tdelay(hp,hp->squeldelay);
  566.                 restore(i_state);
  567.                 return;
  568.             }
  569.             hp->tstate = UNDERRUN; /* Now we expect to underrun */
  570.             /* Send flags on underrun */
  571.             if(hp->speed){ /* If externally clocked */
  572.                 wrtscc(hp->cardbase,cmd,R10,CRCPS|NRZI);
  573.             } else {
  574.                 wrtscc(hp->cardbase,cmd,R10,CRCPS);
  575.             }
  576.             wrtscc(hp->cardbase,cmd,R0,RES_Tx_P); /* reset Tx Int Pend */
  577.         }
  578.         restore(i_state);
  579.         return;     /* back to wait for interrupt */
  580.     } /* end switch */
  581.     restore(i_state);
  582. }
  583.  
  584. /* Pi SIO External/Status interrupts (for the B channel)
  585.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  586.  * Receiver automatically goes to Hunt on an abort.
  587.  *
  588.  * If the Tx Underrun interrupt hits, change state and
  589.  * issue a reset command for it, and return.
  590.  */
  591. static void
  592. b_exint(hp)
  593. register struct pichan *hp;
  594. {
  595.     char st, i_state;
  596.     register int16 cmd;
  597.     char c;
  598.  
  599.     cmd = CTL+hp->base;
  600.     i_state = disable ();        /* disable interrupts */
  601.     hp->exints++;
  602.     st = rdscc(hp->cardbase,cmd,R0);     /* Fetch status */
  603.     /* reset external status latch */
  604.     wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  605.  
  606.  
  607.     switch(hp->tstate){
  608.     case ACTIVE:    /* Unexpected underrun */
  609.         free_p(hp->sndbuf);
  610.         wrtscc(hp->cardbase,cmd,R0,SEND_ABORT);
  611.         hp->tstate = FLAGOUT;
  612.         hp->tunders++;
  613.         tdelay(hp,hp->squeldelay);
  614.         restore(i_state);
  615.         return;
  616.     case UNDERRUN:
  617.         hp->tstate = CRCOUT;
  618.         restore(i_state);
  619.         return;
  620.     case FLAGOUT: 
  621.         /* Find a frame for transmission */
  622.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  623.             /* Nothing to send - return to receive mode
  624.              * Tx OFF now - flag should have gone
  625.              */
  626.             rts(hp,OFF);
  627.             hp->tstate = IDLE;
  628.             restore(i_state);
  629.             return;
  630.         }
  631.         /* Get next char to send */
  632.         pullup(&hp->sndbuf,&c,1);    /* one char at a time */
  633.         wrtscc(hp->cardbase,cmd,R0,RES_Tx_CRC);/* reset for next frame */
  634.  
  635.         /* Send abort on underrun */
  636.         if(hp->speed){ /* If externally clocked */
  637.             wrtscc(hp->cardbase,cmd,R10,CRCPS|NRZI|ABUNDER);
  638.         } else {
  639.             wrtscc(hp->cardbase,cmd,R10,CRCPS|ABUNDER);
  640.         }
  641.  
  642.         wrtscc(hp->cardbase,cmd,R8,c);    /* First char out now */
  643.         wrtscc(hp->cardbase,cmd,R0,RES_EOM_L);/* Reset end of message latch */
  644.  
  645.         /* select transmit interrupts to enable */
  646.  
  647.         wrtscc(hp->cardbase,cmd,R15,TxUIE);    /* allow Underrun int only */
  648.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  649.         wrtscc(hp->cardbase,cmd,R1,TxINT_ENAB|EXT_INT_ENAB);  /* Tx/Extern ints on */
  650.  
  651.         hp->tstate = ACTIVE;    /* char going out now */
  652.         restore(i_state);
  653.         return;
  654.  
  655.     case DEFER:
  656.         /* Check DCD - debounce it
  657.          * See Intel Microcommunications Handbook, p2-308
  658.          */
  659.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  660.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  661.         if((rdscc(hp->cardbase,cmd,R0) & DCD) != 0){
  662.             hp->tstate = DEFER;
  663.             tdelay(hp,100);
  664.             /* defer until DCD transition or timeout */
  665.             wrtscc(hp->cardbase,cmd,R15,CTSIE|DCDIE);
  666.             restore(i_state);
  667.             return;
  668.         }
  669.         /* p - persist calculation */
  670.         if(inportb(hp->cardbase+TMR0) > hp->persist){
  671.             inportb(hp->cardbase+TMR0); /* Discard MSB */
  672.             hp->tstate = DEFER;
  673.             tdelay(hp,hp->slotime);
  674.             restore(i_state);
  675.             return;
  676.         }
  677.         inportb(hp->cardbase+TMR0); /* Discard MSB */
  678.  
  679.         rts(hp,ON);   /* Transmitter on */
  680.         hp->tstate = ST_TXDELAY;
  681.         tdelay(hp,hp->txdelay);
  682.         restore(i_state);
  683.         return;
  684.  
  685.     case ST_TXDELAY:
  686.  
  687.         /* Get next char to send */
  688.         pullup(&hp->sndbuf,&c,1);     /* one char at a time */
  689.         wrtscc(hp->cardbase,cmd,R0,RES_Tx_CRC);/* reset for next frame */
  690.  
  691.         /* Send abort on underrun */
  692.         if(hp->speed){ /* If externally clocked */
  693.             wrtscc(hp->cardbase,cmd,R10,CRCPS|NRZI|ABUNDER);
  694.         } else {
  695.             wrtscc(hp->cardbase,cmd,R10,CRCPS|ABUNDER);
  696.         }
  697.  
  698.         wrtscc(hp->cardbase,cmd,R8,c);    /* First char out now */
  699.         wrtscc(hp->cardbase,cmd,R0,RES_EOM_L);/* Reset end of message latch */
  700.  
  701.         /* select transmit interrupts to enable */
  702.  
  703.         wrtscc(hp->cardbase,cmd,R15,TxUIE);    /* allow Underrun int only */
  704.         wrtscc(hp->cardbase,cmd,R0,RES_EXT_INT);
  705.         /* Tx/Extern ints on */
  706.         wrtscc(hp->cardbase,cmd,R1,TxINT_ENAB|EXT_INT_ENAB);
  707.  
  708.         hp->tstate = ACTIVE;    /* char going out now */
  709.         restore(i_state);
  710.         return;
  711.     }
  712.  
  713.     /* Receive Mode only
  714.      * This triggers when hunt mode is entered, & since an ABORT
  715.      * automatically enters hunt mode, we use that to clean up
  716.      * any waiting garbage
  717.      */
  718.     if((hp->rstate == ACTIVE) && (st & BRK_ABRT)){
  719.         (void) rdscc(hp->cardbase,cmd,R8);
  720.         (void) rdscc(hp->cardbase,cmd,R8);
  721.         (void) rdscc(hp->cardbase,cmd,R8);
  722.         hp->rcp = hp->rcvbuf->data;
  723.         hp->rcvbuf->cnt = 0;          /* rewind on DCD transition */
  724.     }
  725.     restore(i_state);
  726. }
  727.  
  728. /* SET Transmit or Receive Mode
  729.  * Set RTS (request-to-send) to modem on Transmit
  730.  */
  731. static void
  732. rts(hp,x)
  733. register struct pichan *hp;
  734. int16 x;
  735. {
  736.     int16 tc;
  737.     long br;
  738.     int16 cmd;
  739.  
  740.     cmd = CTL+hp->base;
  741.  
  742.     /* Reprogram BRG and turn on transmitter to send flags */
  743.     if(x == ON){    /* Turn Tx ON and Receive OFF */
  744.         /* Exints off first to avoid abort int */
  745.         wrtscc(hp->cardbase,cmd,R15,0);
  746.         wrtscc(hp->cardbase,cmd,R3,Rx8);    /* Rx off */
  747.         hp->rstate = IDLE;
  748.         if(cmd & 2){ /* if channel a */
  749.             /* Set up for TX dma */
  750.             wrtscc(hp->cardbase,cmd,R1,WT_FN_RDYFN|EXT_INT_ENAB);
  751.         } else {
  752.             wrtscc(hp->cardbase,cmd,R1,0);    /* No interrupts */
  753.         }
  754.         if(hp->speed){            /* if internally clocked */
  755.             br = hp->speed;        /* get desired speed */
  756.             tc = (XTAL/br)-2;    /* calc 1X BRG divisor */
  757.             wrtscc(hp->cardbase,cmd,R12,tc&0xFF);     /* lower byte */
  758.             wrtscc(hp->cardbase,cmd,R13,(tc>>8)&0xFF);/* upper byte */
  759.         }
  760.         wrtscc(hp->cardbase,cmd,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);
  761.         /* Transmitter now on */
  762.     } else {    /* Tx OFF and Rx ON */
  763.         hp->tstate = IDLE;
  764.         wrtscc(hp->cardbase,cmd,R5,Tx8|DTR);     /*  TX off */
  765.  
  766.         if(hp->speed){        /* if internally clocked */
  767.             /* Reprogram BRG for 32x clock for receive DPLL */
  768.             /* BRG off, keep Pclk source */
  769.             wrtscc(hp->cardbase,cmd,R14,BRSRC);
  770.             br = hp->speed;            /* get desired speed */
  771.             /* calc 32X BRG divisor */
  772.             tc = ((XTAL/32)/br)-2;
  773.             wrtscc(hp->cardbase,cmd,R12,tc&0xFF);    /* lower byte */
  774.             wrtscc(hp->cardbase,cmd,R13,(tc>>8)&0xFF);/* upper byte */
  775.             /* SEARCH mode, BRG source */
  776.             wrtscc(hp->cardbase,cmd,R14,BRSRC|SEARCH);
  777.             /* Enable the BRG */
  778.             wrtscc(hp->cardbase,cmd,R14,BRSRC|BRENABL);
  779.         }
  780.         /* Now, turn on the receiver and hunt for a flag */
  781.         wrtscc(hp->cardbase,cmd,R3,RxENABLE|RxCRC_ENAB|Rx8);
  782.         hp->rstate = ACTIVE;        /* Normal state */
  783.  
  784.         if(cmd & 2){/* if channel a */
  785.             setup_rx_dma(hp);
  786.         } else {
  787.             /* reset buffer pointers */
  788.             hp->rcp = hp->rcvbuf->data;
  789.             hp->rcvbuf->cnt = 0;
  790.             wrtscc(hp->cardbase,cmd,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  791.         }
  792.         wrtscc(hp->cardbase,cmd,R15,BRKIE);        /* allow ABORT int */
  793.     }
  794. }
  795.  
  796. void
  797. setup_rx_dma(hp)
  798. register struct pichan *hp;
  799. {
  800.     unsigned buf_offset, buf_segment;
  801.     int cmd;
  802.     long longseg, dma_abs, dma_page;
  803.     char i_state;
  804.  
  805.     i_state = disable ();        /* disable interrupts */
  806.  
  807.     cmd = hp->base+CTL;
  808.  
  809.     if(!hp->rcvbuf){
  810.         /* No rx buffer available */
  811.         restore(i_state);
  812.         return;
  813.     }
  814.  
  815.     /* Calculate high order 4 bits of the buffer area and store
  816.      *    them in the DMA page register
  817.      */
  818.     buf_offset = FP_OFF(hp->rcvbuf->data);
  819.     buf_segment= FP_SEG(hp->rcvbuf->data);
  820.     longseg = (long) buf_segment;
  821.     dma_abs = (longseg << 4) + (long) buf_offset;
  822.     dma_page = dma_abs >> 16;
  823.  
  824.     if(((dma_abs + hp->bufsiz -1) >> 16) != dma_page)
  825.         tputs("PI: ERROR - RX DMA page boundary violation\n");
  826.  
  827.     /* Get ready for RX DMA */
  828.     wrtscc(hp->cardbase,cmd,R1,WT_FN_RDYFN|WT_RDY_RT|INT_ERR_Rx|EXT_INT_ENAB);
  829.     outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA chan */
  830.     /* Set DMA mode register to single transfers, incrementing address,
  831.      *    auto init, writes
  832.      */
  833.     outportb(DMA_MODE,DMA_RX_MODE|hp->dmachan);
  834.  
  835.     outportb(hp->page_addr,dma_page);/* Store in  64K DMA page */
  836.     outportb(DMA_RESETFF,0);     /* reset byte pointer flipflop */
  837.     /* Output buffer start (dest) address */
  838.     outportb(hp->dma_dest,dma_abs);
  839.     outportb(hp->dma_dest,dma_abs >> 8);
  840.     /* output DMA maximum byte count */
  841.     outportb(hp->dma_wcr,hp->bufsiz - 1 - sizeof(struct phdr));
  842.     outportb(hp->dma_wcr, (hp->bufsiz - 1 - sizeof(struct phdr)) >> 8);
  843.     /* Unmask channel 1 (start DMA) */
  844.     outportb(DMA_MASK, DMA_ENABLE|hp->dmachan); /* Enable DMA chan */
  845.  
  846.     /* If a packet is already coming in, this line is supposed
  847.      *    to mess up the crc to avoid receiving a partial packet
  848.      */
  849.     wrtscc(hp->cardbase,cmd,R0,RES_Rx_CRC);
  850.  
  851.     /* Enable RX dma */
  852.     wrtscc(hp->cardbase,cmd,R1,WT_RDY_ENAB|WT_FN_RDYFN|WT_RDY_RT|INT_ERR_Rx|EXT_INT_ENAB);
  853.  
  854.     restore(i_state);
  855. }
  856.  
  857. void
  858. setup_tx_dma(hp,buffer,length)
  859. struct pichan *hp;
  860. char *buffer;
  861. int length;
  862. {
  863.     unsigned buf_offset, buf_segment;
  864.     long longseg, dma_abs, dma_page;
  865.     char i_state;
  866.  
  867.     i_state = disable ();        /* disable interrupts */
  868.  
  869.     /* Calculate high order 4 bits of the buffer area and store
  870.      *    them in the DMA page register
  871.      */
  872.  
  873.     buf_offset = FP_OFF(buffer);
  874.     buf_segment= FP_SEG(buffer);
  875.     longseg = (long) buf_segment;
  876.     dma_abs = (longseg << 4) + (long) buf_offset;
  877.     dma_page = dma_abs >> 16;
  878.  
  879.     outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA chan */
  880.     if(((dma_abs + length) >> 16) != dma_page)
  881.         tputs("PI: ERROR - TX DMA page boundary violation\n");
  882.     --length;     /* Adjust length for DMA chip */
  883.     /* Set DMA mode register to single transfers, incrementing address,
  884.      *    no auto init, reads
  885.       */
  886.     outportb(DMA_MODE,DMA_TX_MODE|hp->dmachan);
  887.  
  888.     outportb(hp->page_addr,dma_page); /* Store in 64K DMA page */
  889.     outportb(DMA_RESETFF,0);    /* reset byte pointer flipflop */
  890.     outportb(hp->dma_dest,dma_abs);    /* Output buffer start (source) address */
  891.     outportb(hp->dma_dest,dma_abs >> 8);
  892.     /* output byte count */
  893.     outportb(hp->dma_wcr,length);
  894.     outportb(hp->dma_wcr, (length) >> 8);
  895.  
  896.     restore(i_state);
  897. }
  898.  
  899. /* Initialize pi controller parameters */
  900. static int
  901. scc_init(hp)
  902. register struct pichan *hp;
  903. {
  904.     int16 tc;
  905.     long br;
  906.     char i_state;
  907.     register int16 cmd;
  908.  
  909.     /* Initialize 8530 channel for SDLC operation */
  910.  
  911.     cmd = CTL+hp->base;
  912. #ifdef    notdef
  913.     tprintf("Pi: Initializing Channel %c - Base = %x\n",cmd&2?'A':'B',cmd&~CTL);
  914. #endif
  915.     i_state = disable ();
  916.  
  917.     switch(cmd & 2){
  918.     case 2:
  919.         wrtscc(hp->cardbase,cmd,R9,CHRA);    /* Reset channel A */
  920.         wrtscc(hp->cardbase,cmd,R2,0xff); /* Initialize interrupt vector */
  921.         break;
  922.     case 0:
  923.         wrtscc(hp->cardbase,cmd,R9,CHRB);    /* Reset channel B */
  924.         break;
  925.     }
  926.  
  927.     /* Deselect all Rx and Tx interrupts */
  928.     wrtscc(hp->cardbase,cmd,R1,0);
  929.  
  930.     /* Turn off external interrupts (like CTS/CD) */
  931.     wrtscc(hp->cardbase,cmd,R15,0);
  932.  
  933.     /* X1 clock, SDLC mode */
  934.     wrtscc(hp->cardbase,cmd,R4,SDLC|X1CLK);
  935.  
  936.     /* Now some misc Tx/Rx parameters */
  937.     /* CRC PRESET 1, NRZI Mode */
  938.     if(hp->speed){
  939.         wrtscc(hp->cardbase,cmd,R10,CRCPS|NRZI);
  940.         /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
  941.         wrtscc(hp->cardbase,cmd,R11,TCBR|RCDPLL|TRxCDP|TRxCOI);
  942.     } else {
  943.         wrtscc(hp->cardbase,cmd,R10,CRCPS);
  944.         /* Tx Clk from Trxcl. Rcv Clk from Rtxcl, TRxC pin is input */
  945.         wrtscc(hp->cardbase,cmd,R11,TCTRxCP);
  946.     }
  947.  
  948.     /* Null out SDLC start address */
  949.     wrtscc(hp->cardbase,cmd,R6,0);
  950.  
  951.     /* SDLC flag */
  952.     wrtscc(hp->cardbase,cmd,R7,FLAG);
  953.  
  954.     /* Set up the Transmitter but don't enable it
  955.      *  DTR, 8 bit TX chars only - TX NOT ENABLED
  956.      */
  957.     wrtscc(hp->cardbase,cmd,R5,Tx8|DTR);
  958.  
  959.     /* Receiver - intial setup only - more later */
  960.     wrtscc(hp->cardbase,cmd,R3,Rx8);            /* 8 bits/char */
  961.  
  962.     /* Setting up BRG now - turn it off first */
  963.     wrtscc(hp->cardbase,cmd,R14,BRSRC);         /* BRG off, but keep Pclk source */
  964.  
  965.     /* set the 32x time constant for the BRG in Receive mode */
  966.  
  967.     if(hp->speed){
  968.         br = hp->speed;     /* get desired speed */
  969.         tc = ((XTAL/32)/br)-2;    /* calc 32X BRG divisor */
  970.     } else {
  971.         tc = 14;
  972.     }
  973.  
  974.     wrtscc(hp->cardbase,cmd,R12,tc&0xFF);      /* lower byte */
  975.     wrtscc(hp->cardbase,cmd,R13,(tc>>8)&0xFF); /* upper byte */
  976.  
  977.     /* Following subroutine sets up and ENABLES the receiver */
  978.     rts(hp,OFF);           /* TX OFF and RX ON */
  979.  
  980.     if(hp->speed){
  981.         /* DPLL frm BRG, BRG src PCLK */
  982.         wrtscc(hp->cardbase,cmd,R14,BRSRC|SSBR);
  983.     } else {
  984.         /* DPLL frm rtxc,BRG src PCLK */
  985.         wrtscc(hp->cardbase,cmd,R14,BRSRC|SSRTxC);
  986.     }
  987.     wrtscc(hp->cardbase,cmd,R14,BRSRC|SEARCH); /* SEARCH mode, keep BRG source */
  988.     wrtscc(hp->cardbase,cmd,R14,BRSRC|BRENABL);/* Enable the BRG */
  989.  
  990.     if(!(cmd & 2)) /* if channel b */
  991.         wrtscc(hp->cardbase,cmd,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  992.  
  993.     wrtscc(hp->cardbase,cmd,R15,BRKIE);        /* ABORT int */
  994.  
  995.     /* Now, turn on the receiver and hunt for a flag */
  996.     wrtscc(hp->cardbase,cmd,R3,RxENABLE|RxCRC_ENAB|Rx8);
  997.  
  998.     restore(i_state);
  999.     return 0;
  1000. }
  1001.  
  1002. /* Process to recover from ibuffails.
  1003.  * This could be done in the function network() in config.c,
  1004.  * to save a context switch.  I put it here so the driver would
  1005.  * be more self contained.
  1006. */
  1007. void
  1008. buf_recover(unused,b,a)
  1009. int unused;
  1010. void *b;    /* Unused */
  1011. void *a;    /* Unused */
  1012. {
  1013.     struct pichan *hp0, *hp1;
  1014.     char i_state;
  1015.     int i;
  1016.  
  1017.     for(;;){
  1018.         kwait(NULL);
  1019.  
  1020.         for(i=0; i<pinbr; i++){ /* for each card */
  1021.             hp0 = &Pichan[i];
  1022.             hp1 = &Pichan[i + 1];
  1023.             if(!hp0->rcvbuf){ /* No rx buffer allocated */
  1024.                 i_state = disable ();
  1025.                 hp0->rcvbuf = alloc_mbuf(hp0->bufsiz + sizeof(struct phdr));
  1026.                 if(hp0->rcvbuf != NULLBUF)
  1027.                     hp0->rcvbuf->data += sizeof(struct phdr);
  1028.                 restore(i_state);
  1029.                 setup_rx_dma(hp0);
  1030.             }
  1031.             i_state = disable ();
  1032.             if(!hp1->rcvbuf && (hp1->rstate == ACTIVE)){
  1033.                 /* No rx buf allocated */
  1034.                 if((hp1->rcvbuf = alloc_mbuf(hp1->bufsiz+sizeof(struct phdr))) != NULL){
  1035.                     hp1->rcvbuf->data += sizeof(struct phdr);
  1036.                     hp1->rcp = hp1->rcvbuf->data;
  1037.                     hp1->rcvbuf->cnt = 0;
  1038.                     wrtscc(hp1->cardbase,CTL+hp1->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  1039.                 }
  1040.             }
  1041.             restore(i_state);
  1042.         }
  1043.     }
  1044. }
  1045.  
  1046. /* Attach a PI interface to the system
  1047.  * argv[0]: hardware type, must be "pi"
  1048.  * argv[1]: I/O address, e.g., "0x300"
  1049.  * argv[2]: vector, e.g., "2"
  1050.  * argv[3]: dma channel (1..3)
  1051.  * argv[4]: mode, must be:
  1052.  *        "ax25" (AX.25 UI frame format)
  1053.  * argv[5]: interface label, e.g., "pi0"
  1054.  * argv[6]: receiver packet buffer size in bytes
  1055.  * argv[7]: maximum transmission unit, bytes
  1056.  * argv[8]: channel A interface speed, e.g, "1200", 0 = ext. clock
  1057.  * argv[9]: channel B interface speed
  1058.  * argv[10]: First IP address, optional (defaults to Ip_addr);
  1059.  * argv[11]: Second IP address, optional (defaults to Ip_addr);
  1060.  */
  1061. int
  1062. pi_attach(argc,argv)
  1063. int argc;
  1064. char *argv[];
  1065. {
  1066.     struct mbuf *bp;
  1067.     extern void refiq();
  1068.     register struct iface *if_pca,*if_pcb;
  1069.     struct pichan *hp;
  1070.     int dev;
  1071.     char i_state;
  1072.     int n;
  1073.     char *cp;
  1074.  
  1075.     refiq(); /* replenish interrupt buffer pool (in mbuf.c) */
  1076.     set_acc_delay();
  1077.     /* Quick check to make sure args are good and mycall is set */
  1078.     if(strcmp(argv[4],"ax25") != 0){
  1079.         tprintf("PI: Mode %s unknown for interface %s\n",
  1080.             argv[4],argv[5]);
  1081.         return -1;
  1082.     }
  1083.     if(if_lookup(argv[5]) != NULLIF){
  1084.         tprintf("PI: Interface %s already exists\n",argv[5]);
  1085.         return -1;
  1086.     }
  1087.     if(Mycall[0] == '\0'){
  1088.         tputs("PI: Set mycall first\n");
  1089.         return -1;
  1090.     }
  1091.     /* Note: each card must have a unique address, IRQ and DMA */
  1092.  
  1093.     if(pinbr >= PIMAX){
  1094.         tprintf("PI: Maximum of %d PI cards supported\n",PIMAX);
  1095.         return -1;
  1096.     }
  1097.     dev = pinbr++;
  1098.  
  1099.     /* Initialize hardware-level control structure */
  1100.     Pi[dev].addr = htoi(argv[1]);
  1101.     Pi[dev].vec = htoi(argv[2]);
  1102.  
  1103.     /* Set up counter chip */
  1104.     /* 500 uS square wave */
  1105.     outportb(Pi[dev].addr+TMRCMD, SC0|LSB_MSB|MODE3);
  1106.     for(n=0; n<5;n++) /* satisfy access time restriction */
  1107.         ;
  1108.     outportb(Pi[dev].addr+TMR0, 922 & 0xFF); 
  1109.     for(n=0; n<5;n++) /* satisfy access time restriction */
  1110.         ;
  1111.     outportb(Pi[dev].addr+TMR0, 922 >> 8);
  1112.     for(n=0; n<5;n++) /* satisfy access time restriction */
  1113.         ;
  1114.  
  1115.     /* Save original interrupt vector */
  1116.     Pi[dev].oldvec = getirq(Pi[dev].vec);
  1117.  
  1118.     /* Set new interrupt vector */
  1119.     if(setirq(Pi[dev].vec,pihandle[dev]) == -1){
  1120.         tprintf("PI: IRQ %u out of range\n",Pi[dev].vec);
  1121.         pinbr--;
  1122.         return -1;
  1123.     }
  1124.  
  1125.     if((atoi(argv[3]) < 1) || (atoi(argv[3]) > 3)){
  1126.         tprintf("PI: DMA %d out of range\n",atoi(argv[3]));
  1127.         pinbr--;
  1128.         return -1;
  1129.     }
  1130.  
  1131.     /* Create interface structures and fill in details */
  1132.     if_pca = (struct iface *)callocw(1,sizeof(struct iface));
  1133.     if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
  1134.  
  1135.     if_pca->addr = if_pcb->addr = Ip_addr;
  1136.     if(argc > 10)
  1137.         if_pca->addr = resolve(argv[10]);
  1138.     if(argc > 11)
  1139.         if_pcb->addr = resolve(argv[11]);
  1140.  
  1141.     if(if_pca->addr == 0 || if_pcb->addr == 0){
  1142.         tputs("PI: No IP address");
  1143.         free((char *)if_pca);
  1144.         free((char *)if_pcb);
  1145.         return -1;
  1146.     }
  1147.     /* Append "a" to interface associated with A channel */
  1148.     cp = malloc((unsigned)strlen(argv[5])+2);
  1149.     strcpy(cp,argv[5]);
  1150.     strcat(cp,"a");
  1151.     if_pca->name = cp;
  1152.     /* Append "b" to interface associated with B channel */
  1153.     cp = malloc((unsigned)strlen(argv[5])+2);
  1154.     strcpy(cp,argv[5]);
  1155.     strcat(cp,"b");
  1156.     if_pcb->name = cp;
  1157.  
  1158.     if_pcb->mtu = if_pca->mtu = atoi(argv[7]);
  1159.     if_pcb->type = if_pca->type = CL_AX25;
  1160.     if_pcb->ioctl = if_pca->ioctl = pi_ctl;
  1161.     if_pca->dev = 2*dev;            /* pi0a */
  1162.     if_pcb->dev = 2*dev + 1;        /* pi0b */
  1163.     if_pcb->stop = if_pca->stop = pi_stop;
  1164.     if_pcb->output = if_pca->output = ax_output;
  1165.     if_pcb->raw = if_pca->raw = pi_raw;
  1166.     if_pcb->iface_metric = if_pca->iface_metric = 1;
  1167.  
  1168.     if(strcmp(argv[4],"ax25") == 0){
  1169.         /* Must be true, was checked at top */
  1170.         if_pcb->send = if_pca->send = ax_send;
  1171.         if(if_pcb->hwaddr == NULLCHAR)
  1172.             if_pcb->hwaddr = mallocw(AXALEN);
  1173.         memcpy(if_pcb->hwaddr,Mycall,AXALEN);
  1174.         if(if_pcb->ipcall == NULLCHAR)
  1175.             if_pcb->ipcall = mallocw(AXALEN);
  1176.         memcpy(if_pcb->ipcall,Mycall,AXALEN);
  1177.         if(if_pca->hwaddr == NULLCHAR)
  1178.             if_pca->hwaddr = mallocw(AXALEN);
  1179.         memcpy(if_pca->hwaddr,Mycall,AXALEN);
  1180.         if(if_pca->ipcall == NULLCHAR)
  1181.             if_pca->ipcall = mallocw(AXALEN);
  1182.         memcpy(if_pca->ipcall,Mycall,AXALEN);
  1183.     }
  1184.     /* Link em in to the interface chain */
  1185.     if_pca->next = if_pcb;
  1186.     if_pcb->next = Ifaces;
  1187.     Ifaces = if_pca;
  1188.  
  1189.     /* set params in pichan table for CHANNEL B */
  1190.     hp = &Pichan[2*dev+1];            /* pi1 is offset 1 */
  1191.     hp->dmachan = 0; /* Channel B does not have dma */
  1192.     hp->cardbase = Pi[dev].addr;
  1193.     hp->iface = if_pcb;
  1194.     hp->stata = Pi[dev].addr + CHANA + CTL;    /* permanent status */
  1195.     hp->statb = Pi[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  1196.     hp->speed = (int16)atoi(argv[9]);
  1197.     hp->base = Pi[dev].addr + CHANB;
  1198.     hp->bufsiz = atoi(argv[6]);
  1199.     hp->tstate = IDLE;
  1200.     /* default channel access Params */
  1201.     hp->txdelay = 30;        /* 300 Ms */
  1202.     hp->persist = 128;        /* 50% persistence */
  1203.     hp->slotime = 30;        /* 300 Ms */
  1204.     hp->squeldelay = 3;        /* 30 Ms */
  1205.  
  1206.     wrtscc(hp->cardbase,CTL+hp->stata,R9,FHWRES);     /* Hardware reset */
  1207.                         /* one time only */
  1208.     /* Disable interrupts with Master interrupt ctrl reg */
  1209.     wrtscc(hp->cardbase,CTL+hp->stata,R9,0);
  1210.  
  1211.     scc_init(hp);
  1212.  
  1213.     /* Pre-allocate a receive buffer */
  1214.     i_state = disable ();
  1215.     hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
  1216.     restore(i_state);
  1217.     if(hp->rcvbuf == NULLBUF){
  1218.         /* No memory, abort receiver */
  1219.         tputs("PI: No memory available for receive buffers\n");
  1220.         /* Restore original interrupt vector */
  1221.         setirq(Pi[dev].vec,Pi[dev].oldvec);
  1222.         pinbr--;
  1223.         return -1;
  1224.     }
  1225.     hp->rcvbuf->data += sizeof(struct phdr);
  1226.     hp->rcp = hp->rcvbuf->data;
  1227.     hp->rcvbuf->cnt = 0;
  1228.     hp->sndq = NULLBUF;
  1229.  
  1230.     /* set params in pichan table for CHANNEL A */
  1231.     hp = &Pichan[2*dev];    /* pi0a is offset 0 */
  1232.     hp->dmachan = (unsigned char)atoi(argv[3]);
  1233.     /* Figure out where the dma page register is. */
  1234.     if(hp->dmachan < 8 && hp->dmachan >= 0){
  1235.         hp->page_addr = Page_regs[hp->dmachan];
  1236.     } else {
  1237.         tprintf("PI: DMA channel %d out of range\n",hp->dmachan);
  1238.         free_p(hp->rcvbuf);
  1239.         /* Restore original interrupt vector */
  1240.         setirq(Pi[dev].vec,Pi[dev].oldvec);
  1241.         pinbr--;
  1242.         return -1;
  1243.     }
  1244.  
  1245.     hp->dma_dest = hp->dmachan * 2;
  1246.     hp->dma_wcr = hp->dma_dest + 1;
  1247.  
  1248.     hp->cardbase = Pi[dev].addr;
  1249.     hp->iface = if_pca;
  1250.     hp->speed = (int16)atoi(argv[8]);
  1251.     hp->base = Pi[dev].addr + CHANA;
  1252.     hp->bufsiz = atoi(argv[6]);
  1253.     hp->tstate = IDLE;
  1254.     /* default channel access Params */
  1255.     hp->txdelay = 15;        /* 15 mS */
  1256.     hp->persist = 128;        /* 50% persistence */
  1257.     hp->slotime = 15;        /* 15 mS */
  1258.     hp->squeldelay = 1;        /* 1 mS */
  1259.     newproc("buf_recover",256,buf_recover,0,hp,NULL,0);
  1260.  
  1261.     /* Pre-allocate a receive buffer */
  1262.     /* buffer is allocated with ints off */
  1263.     i_state = disable ();
  1264.     hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
  1265.     restore(i_state);
  1266.     if(hp->rcvbuf == NULLBUF){
  1267.         /* No memory, abort receiver */
  1268.         tputs("PI: No memory available for receive buffers\n");
  1269.         /* Restore original interrupt vector */
  1270.         setirq(Pi[dev].vec,Pi[dev].oldvec);
  1271.         pinbr--;
  1272.         return -1;
  1273.     }
  1274.     hp->rcvbuf->data += sizeof(struct phdr);
  1275.     hp->rcvbuf->cnt = 0;
  1276.     hp->sndq = NULLBUF;
  1277.  
  1278.     /* Get a buffer for tx which does not cross a dma boundary */
  1279.     /* buffer is allocated with ints off */
  1280.     i_state = disable ();
  1281.     bp = alloc_mbuf(hp->bufsiz);
  1282.     if(bp != NULLBUF)
  1283.         hp->txdmabuf = bp->data;
  1284.     else
  1285.         hp->txdmabuf = NULLCHAR;
  1286.     restore(i_state);
  1287.     if(!hp->txdmabuf)
  1288.         tputs("PI: No memory available for transmit buffer");
  1289.  
  1290.     scc_init(hp);
  1291.     /* master interrupt enable */
  1292.     wrtscc(hp->cardbase,CTL+hp->base,R9,MIE|NV);
  1293.  
  1294.     /* Enable interrupt */
  1295.     maskon(Pi[dev].vec);
  1296.  
  1297.     return 0;
  1298. }
  1299.  
  1300. /* Shut down interface */
  1301. int
  1302. pi_stop(iface)
  1303. struct iface *iface;
  1304. {
  1305.     int16 dev;
  1306.     struct pichan *hp;
  1307.  
  1308.     dev = iface->dev;
  1309.     if(dev & 1) /* Because there are 2 devices per card */
  1310.         return 0;
  1311.     dev >>= 1;        /* Convert back into pi number */
  1312.     hp = &Pichan[2*dev];    /* pi0a is offset 0 */
  1313.  
  1314.     outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA channel */
  1315.  
  1316.     /* Turn off interrupts */
  1317.     maskoff(Pi[dev].vec);
  1318.  
  1319.     /* Restore original interrupt vector */
  1320.     setirq(Pi[dev].vec,Pi[dev].oldvec);
  1321.  
  1322.     /* Force hardware reset */
  1323.     wrtscc(((struct pichan *)(&Pichan[2*dev]))->cardbase,
  1324.         CTL+Pi[dev].addr + CHANA,R9,FHWRES);
  1325.  
  1326.     return 0;
  1327. }
  1328.  
  1329. /* Send raw packet on pi card */
  1330. int
  1331. pi_raw(iface,bp)
  1332. struct iface *iface;
  1333. struct mbuf *bp;
  1334. {
  1335.     char i_state;
  1336.     char kickflag;
  1337.     struct pichan *hp;
  1338.  
  1339.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  1340.     iface->rawsndcnt++;
  1341.     iface->lastsent = secclock();
  1342.  
  1343.     hp = &Pichan[iface->dev];
  1344.     kickflag = (hp->sndq == NULLBUF) & (hp->sndbuf == NULLBUF);
  1345.     enqueue(&hp->sndq,bp);
  1346.     hp->enqueued++;
  1347.     if(kickflag){
  1348.         /* simulate interrupt to xmit */
  1349.         switch(hp->base & 2){
  1350.         case 2:
  1351.             a_txint(hp);        /* process interrupt */
  1352.             break;
  1353.         case 0:
  1354.             i_state = disable ();
  1355.             if(hp->tstate == IDLE)
  1356.                 b_txint(hp);
  1357.             restore(i_state);
  1358.             break;
  1359.         }
  1360.     }
  1361.     return 0;
  1362. }
  1363.  
  1364. /* display PI Channel stats */
  1365. int
  1366. dopistat()
  1367. {
  1368.     struct pichan *hp;
  1369.     int i;
  1370.  
  1371.     tputs("PI Board Statistics:\n\n");
  1372.     tputs("Base Addr  Rxints  Txints  Exints  TxFrms  RxFrms  Crcerr  RxOvrs  TxUndr \n");
  1373.     tputs("---------  ------  ------  ------  ------  ------  ------  ------  ------ \n");
  1374.     for(i=0; i<pinbr*2; i++){
  1375.         hp = &Pichan[i];
  1376.  
  1377.         tprintf("0x%03x    % 8lu% 8lu% 8lu% 8u% 8u% 8u% 8u% 8u\nRcv State=%s ",
  1378.          hp->base, hp->rxints, hp->txints, hp->exints, hp->enqueued,
  1379.          hp->rxframes, hp->crcerr, hp->rovers, hp->tunders,
  1380.          hp->rstate==0 ?
  1381.           "IDLE" : hp->rstate==1 ?
  1382.            "ACTIVE" : hp->rstate==2 ?
  1383.             "RXERROR" : hp->rstate==3 ?
  1384.              "RXABORT":"TOOBIG"
  1385.         );
  1386.  
  1387.         tprintf("Tstate = %s\n",
  1388.          hp->tstate == 0 ?
  1389.           "IDLE" : hp->tstate == 1 ?
  1390.            "ACTIVE" : hp->tstate == 2 ?
  1391.             "UNDERRUN" : hp->tstate == 3 ?
  1392.              "FLAGOUT" : hp->tstate == 4 ?
  1393.               "DEFER" : hp->tstate == 5 ?
  1394.                "TXDELAY" : "CRCOUT"
  1395.         );
  1396.     }
  1397.     return 0;
  1398. }
  1399.  
  1400. /* Subroutine to set kiss params in channel tables */
  1401. int32
  1402. pi_ctl(iface,cmd,set,val)
  1403. struct iface *iface;
  1404. int cmd;
  1405. int set;
  1406. int32 val;
  1407. {
  1408.     struct pichan *hp;
  1409.     int32 t,ca;
  1410.  
  1411.     hp = &Pichan[iface->dev]; /* point to channel table */
  1412.     switch(cmd){
  1413.     case PARAM_TXDELAY:
  1414.         if(set)
  1415.             hp->txdelay = val;
  1416.         return hp->txdelay;
  1417.     case PARAM_PERSIST:
  1418.         if(set)
  1419.             hp->persist = val;
  1420.         return uchar(hp->persist);
  1421.     case PARAM_SLOTTIME:
  1422.         if(set)
  1423.             hp->slotime = val;
  1424.         return hp->slotime;
  1425.     case PARAM_TXTAIL:
  1426.         if(set)
  1427.             hp->squeldelay = val;
  1428.         return hp->squeldelay;
  1429.     }
  1430.     return -1;
  1431. }
  1432. #endif /* PI */
  1433. #endif /* MSDOS */
  1434.  
  1435.